package com.ruoyi.web.filter;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Set;

import com.alibaba.fastjson2.JSONObject;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * 包装HttpServletRequest，目的是让其输入流可重复读
 * 
 * @author lincm
 * @date 2022/11/15
 */
@Slf4j
public class ExtRequestWrapper extends HttpServletRequestWrapper {
    /**
     * 存储body数据的容器
     */
    private final byte[] body;
    @Getter
    @Setter
    HashMap<String, String[]> newParam;

    public ExtRequestWrapper(HttpServletRequest request, HashMap<String, String[]> newParam) throws IOException {
        super(request);
        this.newParam = newParam;
        String bodyStr = getBodyString(request);
        // log.info("bodyStr = {}", bodyStr);
        body = bodyStr.getBytes(Charset.forName("UTF-8"));
    }

    /**
     * 获取请求Body
     * 
     * @date 2022-11-15
     * @param request
     * @return String
     */
    public String getBodyString(final ServletRequest request) {
        try {
            return inputStream2String(request.getInputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将inputStream里的数据读取出来并转换成字符串
     */
    private String inputStream2String(InputStream inputStream) {
        StringBuilder sb = new StringBuilder();
        BufferedReader reader = null;
        String bodyStr = null;
        try {
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset()));
            String line;

            if (ObjectUtil.isNull(reader)) {
                return bodyStr;
            }

            while ((line = reader.readLine()) != null) {
                sb.append(line);
                // log.info("sb0 = {}", line);
            }

            JSONObject json = null;
            bodyStr = sb.toString();
            log.info("inputStream >>>>>>>> {}", sb.toString());
            if (JSONUtil.isTypeJSON(bodyStr)) {
                json = JSONObject.parseObject(bodyStr);
                Set<String> set = newParam.keySet();
                for (String key : set) {
                    json.put(key, newParam.get(key)[0]);
                }
                bodyStr = json.toString();
            }
            // log.info("sb = {}", sb.toString());
        } catch (Exception e) {
            log.error("增加参数异常", e);
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    log.error("增加参数-关闭流异常", e);
                }
            }
        }
        log.info("bodyStr = {}", bodyStr);
        return bodyStr;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return inputStream.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {}
        };
    }

    @Override
    public Enumeration<String> getParameterNames() {
        Enumeration<String> enumeration = super.getParameterNames();
        ArrayList<String> list = Collections.list(enumeration);
        newParam.keySet().forEach(key -> {
            list.add(key);
        });
        return Collections.enumeration(list);
    }

    @Override
    public String[] getParameterValues(String name) {
        if (newParam.containsKey(name)) {
            return newParam.get(name);
        }
        return super.getParameterValues(name);
    }
}
